#include "stdafx.h"
#include "CppUnitTest.h"

#include "System/Utility/Testing.h"
#include "System/Base/MapIterator.h"
#include "System/Base/Duad.h"
#include "System/Base/String.h"
#include "System/Base/Buffer.h"
#include "System/Base/ToString.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace Native::System;
using namespace Native { namespace System::Utility;

namespace TestNativeSystem
{
    TEST_CLASS(Map_Tester)
    {
    public:
        CBuffer _base_buffer[6];
        CString _base_texts[6];

        map<CString,CBuffer> InitializeStlMap()
        {
            map<CString,CBuffer> stl_map;

            stl_map[_base_texts[0]] = _base_buffer[0];
            stl_map[_base_texts[1]] = _base_buffer[1];
            stl_map[_base_texts[2]] = _base_buffer[2];
            stl_map[_base_texts[3]] = _base_buffer[3];
            stl_map[_base_texts[4]] = _base_buffer[4];
            stl_map[_base_texts[5]] = _base_buffer[5];

            return move(stl_map);
        }

        Map_Tester()
        {
            _base_texts[0] = L"point";
            _base_texts[1] = L"line";
            _base_texts[2] = L"triangle";
            _base_texts[3] = L"quadrangle";
            _base_texts[4] = L"pentagon";
            _base_texts[5] = L"hexagon";

            _base_buffer[0].Import((POINTER)_base_texts[0].ToCString(), _base_texts[0].Length()*2);
            _base_buffer[1].Import((POINTER)_base_texts[1].ToCString(), _base_texts[1].Length()*2);
            _base_buffer[2].Import((POINTER)_base_texts[2].ToCString(), _base_texts[2].Length()*2);
            _base_buffer[3].Import((POINTER)_base_texts[3].ToCString(), _base_texts[3].Length()*2);
            _base_buffer[4].Import((POINTER)_base_texts[4].ToCString(), _base_texts[4].Length()*2);
            _base_buffer[5].Import((POINTER)_base_texts[5].ToCString(), _base_texts[5].Length()*2);
        }

        void Check(CMap<CString,CBuffer>& testee, CString texts[], CBuffer buffers[], size_t count)
        {
            Assert::AreEqual(testee.Count(), count);

            for (int i = 0; i < count; i++) {
                auto buffer = testee.Value(texts[i]);

                Assert::AreEqual(buffer.Capacity(), _base_buffer[i].Capacity());
                Assert::AreEqual(buffer.Usage(), _base_buffer[i].Usage());
                Assert::AreEqual(buffer.Remain(), _base_buffer[i].Remain());
                Assert::IsTrue(buffer.ImportRule() == _base_buffer[i].ImportRule());

                wchar_t temp[255] = {0};
                buffer.Export((pointer_t)temp, 255);
                
                Assert::AreEqual(_base_texts[i].ToString(), wstring(temp));
            }
        }

        TEST_METHOD(Map_ConstructedByDefault)
        {
            CMap<CString,CBuffer> testee(UToString::FromObject);

            Assert::AreEqual(testee.Count(), 0u);
        }

        TEST_METHOD(Map_ConstructedByStlMap)
        {
            CMap<CString,CBuffer> testee(InitializeStlMap(), UToString::FromObject);

            Check(testee, _base_texts, _base_buffer, 6);
        }

        TEST_METHOD(Map_AddRecord)
        {
            CMap<CString,CBuffer> map(UToString::FromObject);

            for (int i = 0; i < 6; i++){
                map.Add(_base_texts[i], _base_buffer[i]);
            }

            Check(map, _base_texts, _base_buffer, 6);

            function<void(void)> throw_exception = [&]() {
                map.Overlap(false);
                map.Add(CString(L"triangle"), CBuffer());
            };

            Assert::ExpectException<CException>(throw_exception);
        }

        TEST_METHOD(Map_FindElement)
        {
            CMap<CString,CBuffer> map(InitializeStlMap(), UToString::FromObject);

            auto location = map.Find(_base_texts[3]);

            Assert::IsTrue(location.Exist());
        }
    };
}